﻿//
// *************************************************************************************
// WP-Framework
// 
// Developed by
// Lukas Kretschmar (lkretschmar.dev@bluewin.ch)
//
// Switzerland, Copyright (c) 2013 lkretschmar
// This content is released under the MIT License (http://opensource.org/licenses/MIT).
//     
// *************************************************************************************
//
//
			

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using KretschIT.WP_Fx.EasyMoq.Generator.Items;
using KretschIT.WP_Fx.Testing;
using KretschIT.WP_Fx.EasyMoq.Generator.Tests.Helpers.Objects;
using System.Linq;
using System.Collections.Generic;
using KretschIT.WP_Fx.EasyMoq.Generator.Tests.Other;
using KretschIT.WP_Fx.EasyMoq.Generator.Tests.Helpers.Constraints;
using KretschIT.WP_Fx.EasyMoq.Generator.Tests.Helpers.Events;

namespace KretschIT.WP_Fx.EasyMoq.Tests.Generator.Items
{
    [TestClass]
    public class MockableInfoTest
    {
        private IMockableInfo info;
        private INamingFactory nameFactory;

        [TestInitialize]
        public void Init()
        {
            this.nameFactory = new NamingFactory(new List<Type> { typeof(ITestObject), typeof(ITestSimpleGenericObject<string>), typeof(ITestComplexGenericObject<int, string, ITestObject>), typeof(ITestSimpleGenericObject<IObject>), typeof(ITestAllEvent) });
            this.info = new MockableInfo(typeof(ITestObject), this.nameFactory);
        }

        [TestMethod]
        public void Test_MockableInfoCtor()
        {
            Assert.IsNotNull(info.InterfaceType);
            Assert.AreEqual(typeof(ITestObject), this.info.InterfaceType);
            Assert.AreEqual("KretschIT.WP_Fx.EasyMoq.Generator.Tests.Helpers.Objects.ITestObject", this.info.InterfaceName);
            Assert.AreEqual("TestObjectMockable", this.info.MockableName);
            Assert.IsFalse(info.IsGeneric);
        }

        [TestMethod]
        public void Test_MockableInfoCtor_Ohter()
        {
            IMockableInfo info = new MockableInfo(typeof(ITestOtherObject), this.nameFactory);
            Assert.AreEqual(typeof(ITestOtherObject), info.InterfaceType);
            Assert.AreEqual("KretschIT.WP_Fx.EasyMoq.Generator.Tests.Helpers.Objects.ITestOtherObject", info.InterfaceName);
            Assert.AreEqual("TestOtherObjectMockable", info.MockableName);
        }

        [TestMethod]
        public void Test_MockableInfoCtor_NullArgument()
        {
            ExceptionAssert.Throws<ArgumentNullException>(() =>
                {
                    new MockableInfo(null, this.nameFactory);
                });
            ExceptionAssert.Throws<ArgumentNullException>(() =>
                {
                    new MockableInfo(typeof(ITestObject), null);
                });
        }

        [TestMethod]
        public void Test_InterfaceNamespace()
        {
            Assert.AreEqual("KretschIT.WP_Fx.EasyMoq.Generator.Tests.Helpers.Objects", this.info.InterfaceNamespace);
        }

        [TestMethod]
        public void Test_UsingNamespaces()
        {
            Assert.IsNotNull(this.info.UsingNamespaces);
            Assert.AreEqual(3, this.info.UsingNamespaces.Count());
        }

        [TestMethod]
        public void Test_UsingNamespaces_Generic()
        {
            var type = typeof(ITestEmptyGenericObject<IObject>);
            var info = new MockableInfo(type, new NamingFactory(new List<Type> { type }));
            Assert.AreEqual(2, info.UsingNamespaces.Count());
        }

        [TestMethod]
        public void Test_UsingNamespaces_Constraint()
        {
            var type = typeof(IMissUnderstandableGenericConstraint<,>);
            var info = new MockableInfo(type, new NamingFactory(new List<Type> { type }));
            Assert.AreEqual(3, info.UsingNamespaces.Count());
        }

        [TestMethod]
        public void Test_UsingNamespaces_Constraint_GenericInheritance()
        {
            var type = typeof(IComplexGenericConstraint<,>);
            var info = new MockableInfo(type, new NamingFactory(new List<Type> { type }));
            Assert.AreEqual(2, info.UsingNamespaces.Count());
        }

        [TestMethod]
        public void Test_UsingNamespaces_Events()
        {
            var info = new MockableInfo(typeof(ITestAllEvent), this.nameFactory);
            Assert.AreEqual(3, info.UsingNamespaces.Count());
        }

        [TestMethod]
        public void Test_MockableInfoCtor_Generic()
        {
            IMockableInfo info = new MockableInfo(typeof(ITestSimpleGenericObject<string>), this.nameFactory);
            Assert.AreEqual(typeof(ITestSimpleGenericObject<>), info.InterfaceType);
            Assert.AreEqual("KretschIT.WP_Fx.EasyMoq.Generator.Tests.Helpers.Objects.ITestSimpleGenericObject", info.InterfaceName);
            Assert.AreEqual("TestSimpleGenericObject1Mockable", info.MockableName);
            Assert.IsTrue(info.IsGeneric);
        }

        [TestMethod]
        public void Test_MockableInfoCtor_ComplexGeneric()
        {
            IMockableInfo info = new MockableInfo(typeof(ITestComplexGenericObject<int, string, ITestObject>), this.nameFactory);
            var genericType = typeof(ITestComplexGenericObject<int, string, ITestObject>).GetGenericTypeDefinition();
            Assert.AreEqual(genericType, info.InterfaceType);
            Assert.AreEqual("KretschIT.WP_Fx.EasyMoq.Generator.Tests.Helpers.Objects.ITestComplexGenericObject", info.InterfaceName);
            Assert.AreEqual("TestComplexGenericObject3Mockable", info.MockableName);
            Assert.IsTrue(info.IsGeneric);
        }

        [TestMethod]
        public void Test_Represents_NonGeneric()
        {
            Assert.IsTrue(info.Represents(typeof(ITestObject)));
        }

        [TestMethod]
        public void Test_Represents_WrongNonGeneric()
        {
            Assert.IsFalse(info.Represents(typeof(ITestOtherObject)));
        }

        [TestMethod]
        public void Test_Represents_NonGenericVsGeneric()
        {
            Assert.IsFalse(info.Represents(typeof(ITestSimpleGenericObject<string>)));
        }

        [TestMethod]
        public void Test_Represents_Generic()
        {
            var info = new MockableInfo(typeof(ITestSimpleGenericObject<string>), this.nameFactory);
            Assert.IsTrue(info.Represents(typeof(ITestSimpleGenericObject<>)));
            Assert.IsTrue(info.Represents(typeof(ITestSimpleGenericObject<string>)));
            Assert.IsTrue(info.Represents(typeof(ITestSimpleGenericObject<int>)));
            Assert.IsTrue(info.Represents(typeof(ITestSimpleGenericObject<ITestObject>)));
        }

        [TestMethod]
        public void Test_Represents_WrongGeneric()
        {
            var info = new MockableInfo(typeof(ITestSimpleGenericObject<string>), this.nameFactory);
            Assert.IsFalse(info.Represents(typeof(ITestComplexGenericObject<int, string, long>)));
        }

        [TestMethod]
        public void Test_Represents_SameGenericSignature_ButOtherNamespace()
        {
            var info = new MockableInfo(typeof(ITestSimpleGenericObject<string>), this.nameFactory);
            Assert.IsFalse(info.Represents(typeof(KretschIT.WP_Fx.EasyMoq.Generator.Tests.Helpers.OtherObjects.ITestSimpleGenericObject<string>)));
        }

        [TestMethod]
        public void Test_Represents_NullType()
        {
            Assert.IsFalse(info.Represents(null));
        }

        [TestMethod]
        public void Test_AddGenericType_ForNonGenericInterface()
        {
            info.AddGenericTypes(new List<Type> { typeof(string) });
            Assert.IsNotNull(info.GenericVersions);
            Assert.AreEqual(0, info.GenericVersions.Count());
        }

        [TestMethod]
        public void Test_AddGenericType()
        {
            var info = new MockableInfo(typeof(ITestSimpleGenericObject<string>), this.nameFactory);
            info.AddGenericTypes(new List<Type> { typeof(int) });
            Assert.IsNotNull(info.GenericVersions);
            Assert.AreEqual(2, info.GenericVersions.Count());
            Assert.AreEqual(typeof(string), info.GenericVersions.First().Single());
            Assert.AreEqual(typeof(int), info.GenericVersions.Last().Single());
        }

        [TestMethod]
        public void Test_AddGenericType_Null()
        {
            var info = new MockableInfo(typeof(ITestSimpleGenericObject<string>), this.nameFactory);
            info.AddGenericTypes(null);
            Assert.AreEqual(1, info.GenericVersions.Count());
        }

        [TestMethod]
        public void Test_AddGenericType_NullInCollection()
        {
            var info = new MockableInfo(typeof(ITestSimpleGenericObject<string>), this.nameFactory);
            info.AddGenericTypes(new List<Type> { null });
            Assert.AreEqual(1, info.GenericVersions.Count());
        }

        [TestMethod]
        public void Test_AddGenericType_WrongArgumentCount()
        {
            var info = new MockableInfo(typeof(ITestComplexGenericObject<int, string, ITestObject>), this.nameFactory);
            info.AddGenericTypes(new List<Type> { typeof(int), typeof(string), typeof(ITestObject) });
            info.AddGenericTypes(new List<Type>());
            info.AddGenericTypes(new List<Type> { typeof(bool) });
            
            Assert.AreEqual(1, info.GenericVersions.Count());
            var version = info.GenericVersions.Single();
            Assert.AreEqual(3, version.Count());
            Assert.AreEqual(typeof(int), version.First());
            Assert.AreEqual(typeof(string), version.ElementAt(1));
            Assert.AreEqual(typeof(ITestObject), version.Last());
        }

        [TestMethod]
        public void Test_AddGenericType_MultipleTimes()
        {
            var info = new MockableInfo(typeof(ITestComplexGenericObject<int, string, ITestObject>), this.nameFactory);
            info.AddGenericTypes(new List<Type> { typeof(int), typeof(string), typeof(ITestObject) });
            info.AddGenericTypes(new List<Type> { typeof(int), typeof(string), typeof(ITestObject) });

            Assert.AreEqual(1, info.GenericVersions.Count());
        }
    }
}
